`include "define.v"
module alu (
    /*AUTOARG*/
   // Outputs
   e_valE, e_setcc, e_alucc,
   // Inputs
   E_icode, E_ifun, E_valC, E_valB, E_valA, m_stat, w_stat
   );

input   [3:0]   E_icode;
input   [3:0]   E_ifun;
input   [31:0]  E_valC;
input   [31:0]  E_valB;
input   [31:0]  E_valA;
output  [31:0]  e_valE;
output          e_setcc;
output  [2:0]   e_alucc;
// Forwarding Signal
input   [2:0]   m_stat;
input   [2:0]   w_stat;

wire [31:0] e_aluA = 
                   (E_icode == `IIRMOVL) ? E_valC :
                   (E_icode == `IRMMOVL) ? E_valC :
                   (E_icode == `IMRMOVL) ? E_valC :
                   E_valA;
                
wire [31:0] e_aluB = E_valB;

assign e_valE = 
              (E_icode == `IRRMOVL) ? e_aluA :
              (E_icode == `IIRMOVL) ? e_aluA :
              (E_icode == `IRMMOVL) ? e_aluA + e_aluB :
              (E_icode == `IMRMOVL) ? e_aluA + e_aluB :
              (E_icode == `IOPL   ) ? ((E_ifun == `ALU_ADD) ? e_aluA + e_aluB : 
                                    (E_ifun == `ALU_SUB) ? e_aluB - e_aluA :
                                    (E_ifun == `ALU_AND) ? e_aluA & e_aluB :
                                    (E_ifun == `ALU_XOR) ? e_aluA ^ e_aluB :
                                    32'h0000_0000
                                    ) :
              (E_icode == `ICALL  ) ? e_aluB - 32'h4 :
              (E_icode == `IPUSHL ) ? e_aluB - 32'h4 :
              (E_icode == `IRET   ) ? e_aluB + 32'h4 : 
              (E_icode == `IPOPL  ) ? e_aluB + 32'h4 : 
              32'h0000_0000;

// Only IOPL instruction need set cc flags
wire e_setcc = 
                (m_stat != `SAOK) ? 1'b0 : 
                (w_stat != `SAOK) ? 1'b0 : 
                (E_icode == `IOPL)? 1'b1 :
                1'b0;

// Reference pipe.v
// ZF
assign e_alucc[2] = (e_valE == 32'h0000_0000);

// SF
assign e_alucc[1] = e_valE[31];

// OF
assign e_alucc[0] =
    E_ifun == `ALU_ADD ? 
        (e_aluA[31] == e_aluB[31]) & (e_aluA[31] != e_valE[31]) : 
    E_ifun == `ALU_SUB ? 
        (~e_aluA[31] == e_aluB[31]) & (e_aluB[31] != e_valE[31]) : 
    32'h0000_0000; 

endmodule

